#include"Channel.hpp"


using work_t = std::function<void()>;


enum
{
    OK=0,
    UsageError,
    PipeError,
    ForkError
};




// channels is output type parameters
int InitProcessPool(int processnum, std::vector<Channel>& channels, work_t work)
{
    // create nums pipes
    // 1.create pipes
    // 2.create forks
    for(int i = 0;i < processnum;i++)
    {
        // 1.create pipes
        int pipefd[2] = {0};
        int n = pipe(pipefd);

        if(n < 0)
            return PipeError; // create pipes false
        
        // 2.create fork
        pid_t id = fork();
        if(id < 0)
            return ForkError;
        
        // 3.create communication channels
        if(id ==0)
        {
            // son process
            ::close(pipefd[1]); // read

            dup2(pipefd[0],0);  // redirect
            work();  // son process uses pipe to do something
            ::exit(0); // son doesn't return
        }
        
        // father process
        ::close(pipefd[0]); // write
        channels.emplace_back(pipefd[1],id);
        // Channel ch(pipefd[1],id);   
        // channels.push_back(ch);        // when for is over, pipefd is destoryed, so we need a vector to maintain the channels
    }

    return OK;
}


void DispatchTask(std::vector<Channel> channels)
{
    int who = 0;
    // 2. send task
    int num = 20;
    while (num--)
    {
        // a. choose a task
        int task = tm.SelectTask();
        // b. choose a channel
        Channel &curr = channels[who++];
        who %= channels.size();

        std::cout << "######################" << std::endl;
        std::cout << "send " << task << " to " << curr.Name() << ", 任务还剩: " << num << std::endl;
        std::cout << "######################" << std::endl;

        // c. Send task
        curr.Send(task);

        sleep(1);
    }
}



void CleanProcessPool(std::vector<Channel> channels)
{
    // version 3
    // for (auto &c : channels)
    // {
    //     c.Close();
    //     pid_t rid = ::waitpid(c.Id(), nullptr, 0);
    //     if (rid > 0)
    //     {
    //         std::cout << "child " << rid << " wait ... success" << std::endl;
    //     }
    // }

    // version 2
    for(int i = channels.size()-1; i >= 0; i--)
    {
        channels[i].Close();
        pid_t rid = ::waitpid(channels[i].Id(), nullptr, 0); // 阻塞了！
        if (rid > 0)
        {
            std::cout << "child " << rid << " wait ... success" << std::endl;
        }
    }

    // version 1
    // for(auto& c:channels)
    // {
    //     c.Close();
    // }

    // for(auto& c:channels)
    // {
    //     pid_t rid = waitpid(c.Id(),nullptr,0);
    // }
}

